Analyse quantitative des dépenses de soins de ville¶

In [1]:
# Dependencies
#!pip install plotly
#!pip install xlrd

1. Analysez les différentes composantes de la hausse des dépenses de soins de ville entre 2010 et 2019.¶

Au niveau francais dans sa globalite¶

In [2]:
import pandas as pd 
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime

from sklearn.decomposition import PCA
In [3]:
exp = pd.read_excel('données_brutes_cpam_vf.xlsx') # Expenses
exp.head() # No NaNs
Out[3]:
Département Année Omnipraticiens libéraux Spécialistes libéraux Dentistes libéraux Infirmiers libéraux Masseurs kinésithérapeutes libéraux Laboratoires LPP Frais de déplacement des malades Prestations en espèces Total soins de ville
0 1 2010 3.582113e+07 6.444343e+07 21467728.07 27085715.55 17216247.62 2.123551e+07 28271592.30 2.452481e+07 1.008467e+08 3.409128e+08
1 2 2010 4.478957e+07 6.449599e+07 20494481.65 29021929.08 14727914.21 2.254906e+07 38204694.09 3.154759e+07 6.901815e+07 3.348494e+08
2 3 2010 2.551692e+07 3.789959e+07 13197445.20 20639792.20 13171912.57 1.435779e+07 21777766.98 1.883787e+07 4.327667e+07 2.086758e+08
3 4 2010 1.374312e+07 2.117643e+07 5844021.90 15259847.45 8078144.88 8.486306e+06 11472255.18 1.434790e+07 1.978911e+07 1.181971e+08
4 5 2010 1.078393e+07 1.320859e+07 4811436.19 9458520.60 7210305.26 5.575621e+06 8548619.79 9.310945e+06 1.707412e+07 8.598209e+07
In [4]:
exp_gr = exp.groupby(['Année']).agg('sum').reset_index() # Sum per year
year = exp_gr['Année']
exp_gr_perc = exp_gr.pct_change().dropna()
exp_gr_perc['Année'] = year
exp_gr_perc # percentage increase year on year
Out[4]:
Année Omnipraticiens libéraux Spécialistes libéraux Dentistes libéraux Infirmiers libéraux Masseurs kinésithérapeutes libéraux Laboratoires LPP Frais de déplacement des malades Prestations en espèces Total soins de ville
1 2011 0.054165 0.022613 0.008391 0.060670 0.023866 0.017908 0.044253 0.035526 0.025794 0.032526
2 2012 -0.007480 0.005810 0.004859 0.073691 0.047216 -0.017062 0.040825 0.042050 -0.015217 0.012959
3 2013 0.062142 0.022010 0.005229 0.083629 0.064528 0.008333 0.065945 0.056759 0.003087 0.036891
4 2014 0.024483 0.026739 0.006234 0.054909 0.044684 -0.005254 0.057010 0.033408 0.040336 0.033629
5 2015 0.028330 0.041878 0.034892 0.059087 0.036142 0.000893 0.060857 0.038878 0.035321 0.039126
6 2016 0.014915 0.034816 0.015499 0.046523 0.037027 0.023789 0.056922 0.046614 0.040696 0.036436
7 2017 0.027195 0.025717 0.013077 0.042732 0.029900 0.003413 0.045729 0.037118 0.039769 0.031895
8 2018 0.001574 0.042035 0.010243 0.051368 0.034026 -0.001549 0.038450 0.033860 0.052274 0.034439
9 2019 0.094050 0.095079 0.108328 0.100923 0.084022 0.086796 0.111242 0.041637 0.070031 0.087762
In [5]:
# Some stats
# Perc
soins_de_villes_perc = exp_gr_perc['Total soins de ville'].mean() # 3.8 %

# Abs values
tot_soins = pd.DataFrame(exp_gr.sum(), columns=['total de 2010 a 2019'])
tot_soins['poids'] = 100*round(tot_soins['total de 2010 a 2019'] / tot_soins.loc['Total soins de ville','total de 2010 a 2019'],2)
tot_soins = tot_soins.sort_values('poids', ascending=False)
tot_soins
Out[5]:
total de 2010 a 2019 poids
Total soins de ville 4.678051e+11 100.0
Prestations en espèces 9.628912e+10 21.0
Spécialistes libéraux 9.393026e+10 20.0
Omnipraticiens libéraux 5.704222e+10 12.0
Infirmiers libéraux 4.966443e+10 11.0
LPP 4.997623e+10 11.0
Masseurs kinésithérapeutes libéraux 3.044648e+10 7.0
Frais de déplacement des malades 3.419082e+10 7.0
Dentistes libéraux 2.728325e+10 6.0
Laboratoires 2.898227e+10 6.0
Année 2.014500e+04 0.0
In [6]:
fig = px.line(
    exp_gr,
    x='Année',
    y=sorted([col for col in list(exp_gr.columns) if col not in ['Année', 'Total soins de ville']]),
    width=1000, height=700,
    markers=True,
    title = "Dépense des soins de ville entre 2010 et 2019 en France - En Milliards d '€",
    template="simple_white",
    labels={
        'variable':'poste de dépense',
        'value':'Dépense'
    }
)
fig.update_yaxes( # the y-axis is in euros
    tickprefix="€", showgrid=True
)
fig.add_shape( # add a vartical "target" line
    type="line", line_color="salmon", line_width=3, opacity=1, line_dash="dot",
    x0=2018, x1=2018, xref="x", y0=0, y1=12e9, yref="y"
)
fig.add_annotation( # Text 
    text="accélération de la hausse", x=2018, y=8e9, arrowhead=1, showarrow=False
)

fig.show()
In [7]:
exp_gr_pivot = exp_gr.melt( # Pivot
    id_vars='Année',
    var_name='Composante', 
    value_name="Dépense"
)

fig = px.bar(
    exp_gr_pivot[(exp_gr_pivot['Année']==2019) & (exp_gr_pivot['Composante']!='Total soins de ville')] \
        .sort_values('Dépense', ascending=False),
    x='Composante',
    y='Dépense',
    width=1000, height=700,
    title = "Dépenses en soins de ville pour l'année 2019 - En Milliards d '€",
    template="simple_white"
)
fig.update_yaxes( # the y-axis is in euros
    tickprefix="€", showgrid=True
)

Commentaire:

France - Par An Les soins de ville voient leur valeur augmenter constamment entre 2010 et 2019 passant de 40.3 a 56.6 milliards d'euros de depenses (augmentation de +40%). Si l'evolution est plutot constante d'annee en annee, aux alentours de +3%, on remarque une forte hausse entre 2018 et 2019 (+9%). Quelles sont les causes/composantes principales expliquant une telle hausse? Tout d'abord, les soins de villes, dans leur entierete entre 2010 et 2019, ont represente une depense considerable de 467 milliards d'euros: celle ci-est majoritairement due aux Prestations en espèces et Spécialistes libéraux qui representent a eux seuls 190 milliards d'euros, i.e. 41% de la depense totale. Suivent ensuite les Omnipraticiens libéraux, Infirmiers libéraux et LPP, chacun contribuant pour ~10% de la depense totale. On constate enfin que tous les postes de dépense sont en hausse constante d'annee en annee.

En termes de comportement des depenses on observe trois clusters principaux: un premier groupe incluant les Prestations en espèces et Spécialistes libéraux comme souligne ci-dessus. Ce groupe est le vecteur principal des depenses avec une augmentation assez prononcee dans la periode d'interet. Le deuxieme groupe inclut les Omnipraticiens libéraux, Infirmiers libéraux et LPP avec une correlation des depenses tres importante des LPP et Infirmiers libéraux, leur depenses etant quasi juxtaposees. Enfin, le troisieme groupe inclut les Frais de déplacement des malades, Masseurs kinésithérapeutes libéraux, Laboratoires et Dentistes libéraux. Ce dernier, affiche en 2019 des depenses entre 2 et 3 milliards d'euros et a une hausse legerement plus attenuee par rapport aux deux premiers clusters

Par Departement¶

In [8]:
exp.head()
Out[8]:
Département Année Omnipraticiens libéraux Spécialistes libéraux Dentistes libéraux Infirmiers libéraux Masseurs kinésithérapeutes libéraux Laboratoires LPP Frais de déplacement des malades Prestations en espèces Total soins de ville
0 1 2010 3.582113e+07 6.444343e+07 21467728.07 27085715.55 17216247.62 2.123551e+07 28271592.30 2.452481e+07 1.008467e+08 3.409128e+08
1 2 2010 4.478957e+07 6.449599e+07 20494481.65 29021929.08 14727914.21 2.254906e+07 38204694.09 3.154759e+07 6.901815e+07 3.348494e+08
2 3 2010 2.551692e+07 3.789959e+07 13197445.20 20639792.20 13171912.57 1.435779e+07 21777766.98 1.883787e+07 4.327667e+07 2.086758e+08
3 4 2010 1.374312e+07 2.117643e+07 5844021.90 15259847.45 8078144.88 8.486306e+06 11472255.18 1.434790e+07 1.978911e+07 1.181971e+08
4 5 2010 1.078393e+07 1.320859e+07 4811436.19 9458520.60 7210305.26 5.575621e+06 8548619.79 9.310945e+06 1.707412e+07 8.598209e+07
In [9]:
exp_pivot = exp.melt( # Pivot
    id_vars=['Département','Année'],
    var_name='Composante', 
    value_name="Dépense"
)
exp_pivot_top3_tot = exp_pivot[exp_pivot.groupby('Année')['Dépense'].rank(ascending=False).le(3)]
exp_pivot_top3_tot['Département'] = exp_pivot_top3_tot['Département'].astype('str').replace(to_replace={
    '13':'Bouches-du-Rhône',
    '59':'Nord',
    '69':'Rhône',
    '75':'Paris'
})
exp_pivot_top3_tot
C:\Users\nicco\anaconda3\envs\test-env\lib\site-packages\ipykernel_launcher.py:11: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

Out[9]:
Département Année Composante Dépense
8652 Bouches-du-Rhône 2010 Total soins de ville 1.997630e+09
8697 Nord 2010 Total soins de ville 1.792959e+09
8713 Paris 2010 Total soins de ville 1.283393e+09
8748 Bouches-du-Rhône 2011 Total soins de ville 2.045580e+09
8793 Nord 2011 Total soins de ville 1.873293e+09
8809 Paris 2011 Total soins de ville 1.288387e+09
8844 Bouches-du-Rhône 2012 Total soins de ville 2.060623e+09
8889 Nord 2012 Total soins de ville 1.914837e+09
8905 Paris 2012 Total soins de ville 1.295414e+09
8940 Bouches-du-Rhône 2013 Total soins de ville 2.151754e+09
8985 Nord 2013 Total soins de ville 1.986267e+09
9001 Paris 2013 Total soins de ville 1.314424e+09
9036 Bouches-du-Rhône 2014 Total soins de ville 2.205873e+09
9081 Nord 2014 Total soins de ville 2.076888e+09
9097 Paris 2014 Total soins de ville 1.352763e+09
9132 Bouches-du-Rhône 2015 Total soins de ville 2.287674e+09
9177 Nord 2015 Total soins de ville 2.157864e+09
9193 Paris 2015 Total soins de ville 1.370263e+09
9228 Bouches-du-Rhône 2016 Total soins de ville 2.351559e+09
9273 Nord 2016 Total soins de ville 2.232632e+09
9289 Paris 2016 Total soins de ville 1.417495e+09
9324 Bouches-du-Rhône 2017 Total soins de ville 2.400885e+09
9369 Nord 2017 Total soins de ville 2.296586e+09
9385 Paris 2017 Total soins de ville 1.454464e+09
9420 Bouches-du-Rhône 2018 Total soins de ville 2.468346e+09
9465 Nord 2018 Total soins de ville 2.378330e+09
9475 Rhône 2018 Total soins de ville 1.507025e+09
9516 Bouches-du-Rhône 2019 Total soins de ville 2.650593e+09
9561 Nord 2019 Total soins de ville 2.539484e+09
9577 Paris 2019 Total soins de ville 1.628976e+09
In [10]:
fig = px.scatter(
    exp[['Année','Total soins de ville', 'Département']],
    x='Année',
    y='Total soins de ville',
    template="simple_white",
    hover_data = ['Département'],
    title = "Dépenses en soins de ville par departement entre 2010 et 2019 - En Milliards d '€"
)
fig.update_yaxes( # the y-axis is in euros
    tickprefix="€", showgrid=True
)
In [11]:
exp_pivot_tail3_tot = exp_pivot[exp_pivot.Composante=='Total soins de ville'] 
exp_pivot_tail3_tot = exp_pivot_tail3_tot[exp_pivot_tail3_tot.groupby('Année')['Dépense'].rank(ascending=True).le(1)] # Min values
exp_pivot_tail3_tot['Dépense - Moyenne mobile sur 3 ans'] = exp_pivot_tail3_tot['Dépense'].rolling(3).mean()
exp_pivot_tail3_tot
Out[11]:
Département Année Composante Dépense Dépense - Moyenne mobile sur 3 ans
8686 48 2010 Total soins de ville 4.121377e+07 NaN
8782 48 2011 Total soins de ville 4.265398e+07 NaN
8878 48 2012 Total soins de ville 4.312395e+07 4.233057e+07
8974 48 2013 Total soins de ville 4.458788e+07 4.345527e+07
9070 48 2014 Total soins de ville 4.649024e+07 4.473402e+07
9166 48 2015 Total soins de ville 4.805181e+07 4.637664e+07
9262 48 2016 Total soins de ville 4.924266e+07 4.792824e+07
9358 48 2017 Total soins de ville 4.958974e+07 4.896140e+07
9454 48 2018 Total soins de ville 5.055527e+07 4.979589e+07
9550 48 2019 Total soins de ville 5.781228e+07 5.265243e+07
In [12]:
exp_pivot_sub = exp_pivot[exp_pivot.Composante != 'Total soins de ville']
exp_pivot_sub
exp_pivot_sub_gr = exp_pivot_sub[exp_pivot_sub.groupby(['Année','Département'])['Dépense'] \
                    .rank(ascending=False) \
                    .le(1)]\
                    .sort_values(['Année','Dépense'], ascending=[True,False]) \
                    .groupby(['Année'])['Composante'] \
                    .value_counts() \
                    .to_frame(name='fréquence') \
                    .reset_index()
exp_pivot_sub_gr['pourcentage'] = 100 * exp_pivot_sub_gr['fréquence'] / 96 # 96: number of departements
exp_pivot_sub_gr
Out[12]:
Année Composante fréquence pourcentage
0 2010 Prestations en espèces 59 61.458333
1 2010 Spécialistes libéraux 35 36.458333
2 2010 Frais de déplacement des malades 1 1.041667
3 2010 Infirmiers libéraux 1 1.041667
4 2011 Prestations en espèces 58 60.416667
5 2011 Spécialistes libéraux 35 36.458333
6 2011 Infirmiers libéraux 2 2.083333
7 2011 Frais de déplacement des malades 1 1.041667
8 2012 Prestations en espèces 57 59.375000
9 2012 Spécialistes libéraux 36 37.500000
10 2012 Infirmiers libéraux 2 2.083333
11 2012 Frais de déplacement des malades 1 1.041667
12 2013 Prestations en espèces 56 58.333333
13 2013 Spécialistes libéraux 36 37.500000
14 2013 Infirmiers libéraux 3 3.125000
15 2013 Frais de déplacement des malades 1 1.041667
16 2014 Prestations en espèces 59 61.458333
17 2014 Spécialistes libéraux 33 34.375000
18 2014 Infirmiers libéraux 3 3.125000
19 2014 Frais de déplacement des malades 1 1.041667
20 2015 Prestations en espèces 57 59.375000
21 2015 Spécialistes libéraux 35 36.458333
22 2015 Infirmiers libéraux 3 3.125000
23 2015 Frais de déplacement des malades 1 1.041667
24 2016 Prestations en espèces 59 61.458333
25 2016 Spécialistes libéraux 33 34.375000
26 2016 Infirmiers libéraux 3 3.125000
27 2016 Frais de déplacement des malades 1 1.041667
28 2017 Prestations en espèces 58 60.416667
29 2017 Spécialistes libéraux 33 34.375000
30 2017 Infirmiers libéraux 4 4.166667
31 2017 Frais de déplacement des malades 1 1.041667
32 2018 Prestations en espèces 60 62.500000
33 2018 Spécialistes libéraux 30 31.250000
34 2018 Infirmiers libéraux 4 4.166667
35 2018 Frais de déplacement des malades 2 2.083333
36 2019 Prestations en espèces 60 62.500000
37 2019 Spécialistes libéraux 31 32.291667
38 2019 Infirmiers libéraux 4 4.166667
39 2019 Frais de déplacement des malades 1 1.041667
In [13]:
fig = px.bar(
    exp_pivot_top3_tot,
    x='Année',
    y='Dépense',
    color= 'Département',
    width=1000, height=700,
    title = "Top-3 des Départements par dépense en soins de ville - de 2010 à 2019 en Milliards d '€",
    barmode='group',
    template="simple_white"
)
fig.update_yaxes( # the y-axis is in dollars
    tickprefix="€", showgrid=True
)
fig.update_layout( # customize font and legend orientation & position
    #font_family="Rockwell",
    legend=dict(
        title=None, orientation="h", y=1, yanchor="bottom", x=0.5, xanchor="center"
    )
)
fig.show()
In [14]:
fig = px.bar(
    exp_pivot_sub_gr,
    x='Année',
    y='pourcentage',
    color= 'Composante',
    width=1000, height=700,
    title = "Distribution de la première dépense de soins par département",
    #barmode='group',
    template="simple_white"
)
fig.update_yaxes( # the y-axis is in dollars
  ticksuffix="%",showgrid=True
)
fig.update_layout( # customize font and legend orientation & position
    #font_family="Rockwell",
    legend=dict(
        title=None, orientation="h", y=1, yanchor="bottom", x=0.5, xanchor="center"
    )
)
fig.show()

Commentaire:

Par Departement - Par An En analysant plus en detail les depenses de soins de ville par departement on remarque que deux departements se distinguent: les Bouches-du-Rhône avec des depenses constamment en hausse et atteignant les 2.6 milliards d'euros en 2019 et le departement du Nord avec une croissance similaire et 2.5 milliards d'euros en 2019. Suit ensuite Paris, chaque annee, a la troisieme place avec une depense bien inferieur (60% seulement par rapport aux Bouches-du-Rhône en 2019) et le Rhône qui apparait exceptionnellement dans le top-3 en 2018.

En s'interessant plus specifiquement aux depenses de soins majoritaires par departement (cf FIG) on retrouve les Prestations en espèces en tant que premiere depense de soins pour environ 60 des 96 departements de France chaque annee, le chiffre etant tres stable entre 2010 et 2019. On trouve ensuite les depenses liees aux Spécialistes libéraux comme etant la premiere depense pour environ 34 departements avec une legere baisse en 2019. Moins de 5% des departement ont une depense primaire autre que les Prestations en espèces et les Spécialistes libéraux (les Frais de déplacement des malades et Infirmiers libéraux).

De l'autre cote du spectre, on observe chaque annee des departements avec des depenses bien plus basses avec des valeurs proches de quelques dizaines de millions d'euros seuelement. Cependant, meme lorsqu'on s'interesse aux depenses minimales, on retrouve tout de meme une hausse des depenses, par example en Lozere, avec une moyenne mobile de ses depenses, sur les trois dernieres annees, ayant augmente de 24% entre 2012 et 2019 (58 millions d'euros en 2019).

En conclusion, on constate une hausse significative des soins de ville entre 2010 et 2019 avec les Prestations en espèces et Spécialistes libéraux etant les depenses plus importantes chaque annee. Au niveaux des differents departements, les Bouches-du-Rhône et le Nord engendrent plus de depenses et la Lozere clot le classement avec une depense 4x fois inferieure par rapport aux Bouches-du-Rhône. Cela demontre une hétérogénéité de la demande en soins de ville entre les départements qui peut potentiellement s'expliquer en prenant en compte des donnees supplementaires telles que les estimations de population par département, sexe et tranche d’âge ainsi que le nombre d’ALP (affections de longue durée) par département et par type d’ALD.

2. À l’aide d’un modèle, expliquez l’hétérogénéité de la demande en soins de ville entre départements pour l’année 2019 à partir des données démographiques et des données d’affectation de longue durée pour cette même année.¶

In [15]:
exp19 = exp[exp.Année==2019]
exp19['Département'] = exp19['Département'].astype('str')

px.violin(
    exp19,
    y="Total soins de ville",
    width=1000, height=700,
    template="simple_white",
    title = 'Hétérogénéité des dépenses en soins de ville entre les départements en 2019',
    box=True
         )
C:\Users\nicco\anaconda3\envs\test-env\lib\site-packages\ipykernel_launcher.py:2: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

In [16]:
# Population estimate
pop = pd.read_excel(
    'estim-pop-dep-sexe-gca-1975-2021.xlsx',
    sheet_name = '2019',
    header = [3,4]
) 
pop.columns = pop.columns.map('_'.join).str.strip('_')
pop = pop.rename(columns={
        'Départements_Unnamed: 0_level_1':'Département',
        'Départements_Unnamed: 1_level_1':'Nom du département',
})
pop = pop.dropna(subset=['Département'])
pop = pop[:-1] # Source : Insee - Estimations de population (résultats provisoires arrêtés fin 2020)
pop_fm = pop.loc[96,:]
pop_dom = pop[pop.Département == 'DOM']
pop_fm_dom = pop[pop.Département == 'France métropolitaine et DOM']
pop = pop[~pop.Département.isin([
    'France métropolitaine ', 'DOM', 'France métropolitaine et DOM'
])] 
pop.head()
Out[16]:
Département Nom du département Ensemble_0 à 19 ans Ensemble_20 à 39 ans Ensemble_40 à 59 ans Ensemble_60 à 74 ans Ensemble_75 ans et plus Ensemble_Total Hommes_0 à 19 ans Hommes_20 à 39 ans Hommes_40 à 59 ans Hommes_60 à 74 ans Hommes_75 ans et plus Hommes_Total Femmes_0 à 19 ans Femmes_20 à 39 ans Femmes_40 à 59 ans Femmes_60 à 74 ans Femmes_75 ans et plus Femmes_Total
0 01 Ain 168091.0 151167.0 178448.0 102042.0 53112.0 652860.0 86874.0 75432.0 89041.0 49114.0 21362.0 321823.0 81217.0 75735.0 89407.0 52928.0 31750.0 331037.0
1 02 Aisne 132910.0 115437.0 137721.0 96234.0 48683.0 530985.0 68421.0 57832.0 68188.0 46110.0 18188.0 258739.0 64489.0 57605.0 69533.0 50124.0 30495.0 272246.0
2 03 Allier 68963.0 62009.0 87142.0 71555.0 45868.0 335537.0 35605.0 31302.0 42841.0 33500.0 17570.0 160818.0 33358.0 30707.0 44301.0 38055.0 28298.0 174719.0
3 04 Alpes-de-Haute-Provence 34398.0 30454.0 43971.0 34900.0 20940.0 164663.0 18068.0 15171.0 21352.0 16909.0 8522.0 80022.0 16330.0 15283.0 22619.0 17991.0 12418.0 84641.0
4 05 Hautes-Alpes 30038.0 27524.0 38137.0 28913.0 15945.0 140557.0 15639.0 13819.0 18804.0 13947.0 6382.0 68591.0 14399.0 13705.0 19333.0 14966.0 9563.0 71966.0
In [17]:
# ALD
ald = pd.read_excel('ALD-prevalentes-par-departement_serie-annuelle_vf.xls') 
ald = ald.rename(columns={
        'Code département':'Département',
        'Total':'Total ALD',
})
ald = ald[:-3] # Pour Mayotte...
ald.head()
Out[17]:
Département Nom du département Total ALD Insuffisance cardiaque grave, troubles du rythme graves, cardiopathies valvulaires graves, cardiopathies congénitales graves (ALD5) Diabète de type 1 et diabète de type 2 (ALD8) Maladie coronaire (ALD13) Affections psychiatriques de longue durée (ALD23) Tumeur maligne, affection maligne du tissu lymphatique ou hématopoïétique (ALD30)
0 01 Ain 20643.0 1963.0 4565.0 1994.0 2122.0 3873
1 02 Aisne 23514.0 2199.0 6284.0 2417.0 2160.0 3718
2 03 Allier 25140.0 2151.0 5169.0 2370.0 3503.0 4353
3 04 Alpes-de-Haute-Provence 23538.0 2065.0 4135.0 2143.0 3540.0 3887
4 05 Hautes-Alpes 23613.0 2367.0 3490.0 1941.0 3462.0 3945
In [18]:
pop['Département'] = pop['Département'].astype('str').str.strip()
ald['Département'] = ald['Département'].astype('str').str.strip()

df = ald.merge(pop.drop('Nom du département',axis=1), how='left', on='Département')# No NaNs

for col in df.columns[2:]: 
    df[col] = df[col].astype('int')
In [19]:
# Add expenses as well
exp19['Département'] = exp19['Département'].replace({
    '1':'01','2':'02','3':'03','4':'04',
    '5':'05','6':'06','7':'07','8':'08',
    '9':'09'
})

df = df.merge(exp19[['Total soins de ville','Département']], how='left', on='Département').dropna() # DOM 
df.head()
C:\Users\nicco\anaconda3\envs\test-env\lib\site-packages\ipykernel_launcher.py:5: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

Out[19]:
Département Nom du département Total ALD Insuffisance cardiaque grave, troubles du rythme graves, cardiopathies valvulaires graves, cardiopathies congénitales graves (ALD5) Diabète de type 1 et diabète de type 2 (ALD8) Maladie coronaire (ALD13) Affections psychiatriques de longue durée (ALD23) Tumeur maligne, affection maligne du tissu lymphatique ou hématopoïétique (ALD30) Ensemble_0 à 19 ans Ensemble_20 à 39 ans ... Hommes_60 à 74 ans Hommes_75 ans et plus Hommes_Total Femmes_0 à 19 ans Femmes_20 à 39 ans Femmes_40 à 59 ans Femmes_60 à 74 ans Femmes_75 ans et plus Femmes_Total Total soins de ville
0 01 Ain 20643 1963 4565 1994 2122 3873 168091 151167 ... 49114 21362 321823 81217 75735 89407 52928 31750 331037 5.106213e+08
1 02 Aisne 23514 2199 6284 2417 2160 3718 132910 115437 ... 46110 18188 258739 64489 57605 69533 50124 30495 272246 4.581757e+08
2 03 Allier 25140 2151 5169 2370 3503 4353 68963 62009 ... 33500 17570 160818 33358 30707 44301 38055 28298 174719 2.888785e+08
3 04 Alpes-de-Haute-Provence 23538 2065 4135 2143 3540 3887 34398 30454 ... 16909 8522 80022 16330 15283 22619 17991 12418 84641 1.667391e+08
4 05 Hautes-Alpes 23613 2367 3490 1941 3462 3945 30038 27524 ... 13947 6382 68591 14399 13705 19333 14966 9563 71966 1.269668e+08

5 rows × 27 columns

Modele 1.a XgBoost Regression - Tot ALD as a proxy for demand¶

In [20]:
y = df['Total ALD']
X = df.drop(columns=['Total ALD','Département','Nom du département'], axis=1)
In [21]:
from xgboost import XGBRegressor, XGBClassifier, plot_tree
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, mean_absolute_percentage_error, accuracy_score, confusion_matrix


model = XGBRegressor()

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.10, random_state=42, shuffle=True
)

model.fit(X_train, y_train)
y_pred = model.predict(X_test)

mae = mean_absolute_error(y_test,y_pred)
mape = mean_absolute_percentage_error(y_test,y_pred)
print('mae:',mae)
print('mape:',mape*100)
mae: 593.5298828125
mape: 2.7662334721251076

Conclusion: Precis mais ne necessite que "Insuffisance cardiaque grave, troubles du rythme graves, cardiopathies valvulaires graves, cardiopathies congénitales graves (ALD5)" pour prendre une decision, cela n'ait pas utile pour expliquer Hétérogénéité des depenses en soins de ville

Modele 1.b XgBoost Regression - Tot ALD as a proxy for demand¶

In [22]:
def categorise(x):
    if x<0.5e9: # 0.5B €
        return 'Moins de 0.5 milliards'
    elif x>0.5e9 and x<1e9:
        return 'Entre 0.5 et 1 milliards'
    elif x>1e9 and x<1.5e9:
        return 'Entre 1 et 1.5 milliards'
    elif x>1.5e9:
        return 'Plus de 1.5 milliards'
    
df['categorie de dépense'] = df['Total soins de ville'].apply(categorise)
df['categorie de dépense'].value_counts()
Out[22]:
Moins de 0.5 milliards      55
Entre 0.5 et 1 milliards    20
Entre 1 et 1.5 milliards    16
Plus de 1.5 milliards        5
Name: categorie de dépense, dtype: int64
In [23]:
y = df['categorie de dépense']
X = df.drop(columns=['categorie de dépense','Département','Nom du département', 'Total soins de ville'], axis=1)
In [24]:
model = XGBClassifier()

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.20, random_state=42, shuffle=True
)

model.fit(X_train, y_train)
y_pred = model.predict(X_test)

acc = accuracy_score(y_test,y_pred)
print('accuracy:',acc) # 85 %
print(confusion_matrix(y_test,y_pred))
C:\Users\nicco\anaconda3\envs\test-env\lib\site-packages\xgboost\sklearn.py:1146: UserWarning:

The use of label encoder in XGBClassifier is deprecated and will be removed in a future release. To remove this warning, do the following: 1) Pass option use_label_encoder=False when constructing XGBClassifier object; and 2) Encode your labels (y) as integers starting with 0, i.e. 0, 1, 2, ..., [num_class - 1].

[10:35:32] WARNING: C:/Users/Administrator/workspace/xgboost-win64_release_1.4.0/src/learner.cc:1095: Starting in XGBoost 1.3.0, the default evaluation metric used with the objective 'multi:softprob' was changed from 'merror' to 'mlogloss'. Explicitly set eval_metric if you'd like to restore the old behavior.
accuracy: 0.85
[[4 0 1 0]
 [0 3 0 0]
 [1 0 8 0]
 [0 1 0 2]]
In [28]:
import matplotlib.pyplot as plt
plt.figure()
plot_tree(model)
plt.savefig('tree.svg', format='svg', dpi=1200)
<Figure size 432x288 with 0 Axes>

Conclusion: Bien meilleurs resultats en utilisant le total des soins de ville en tant que variable dependendante et en construisant des categories de depenses de facon telle a avoir assez d'observables dans chacune des categories (choisies grace au violin plot) afin de pouvoir entrainer un algorithme d'apprentissage statistique sur un probleme de classification. Avec un training set tres reduit de seulement 76 observables et un test set de 26 observabables le modele arrive a predire correctement la categorie de depense avec une accuracy de 85 %. Plus precisesement, etant les quatre classes de depenses on remarque, en s'appuyant sur la matrice de confusion, que seules 3 observables donnent des predictions fausses. De plus, la matrice de confusion nous montre aussi que des examples pour chaque classe apparaissent dans le test set, ce qui nous indique que l'algorithme peut s'appuyer sur toutes les regles apprisent pour faire son choix.

Quatre regles emergeant de l'algorithme sont les suivantes:

  • Le nombre d'hommes de plus de 75 est moins que ~23k: Si oui, stop
  • Non a la Regle precedente et Le nombre de femmes de 40 a 59 est moins que ~143k: Si non, stop
  • Non a la premiere regle, Oui a la deuxieme et enfin s'ínteresser a l'ensemble, femmes et hommes entre 40 et 59 ans pour prendre la decision finale

Afin d'expliquer l'hétérogénéité des depenses en soins de ville entre les département il convient maintenant de verifier dans quelles proportions ses regles s'appliquent sur l'ensemble des donnees

In [29]:
# Apply rules from decision tree
df1 = df[df['Hommes_75 ans et plus'] < 23127.5] # 52 rows - Majority "Moins de 0.5 milliards"

df2 = df[(df['Hommes_75 ans et plus'] > 23127.5) & (df['Femmes_40 à 59 ans'] > 143373.5)] # 21 rows - HIgh level of expenses, Entre 1 et 1.5 milliards (16) Plus de 1.5 milliard  5

df3 = df[(df['Hommes_75 ans et plus'] > 23127.5) &
    (df['Femmes_40 à 59 ans'] < 143373.5) &
    (df['Ensemble_40 à 59 ans'] < 160918.5) # 6 rows - low expenses spectrum
  ] 

df4 = df[(df['Hommes_75 ans et plus'] > 23127.5) &
    (df['Femmes_40 à 59 ans'] < 143373.5) &
    (df['Ensemble_40 à 59 ans'] > 160918.5) # 17 rows - Majority "Entre 0.5 et 1 milliards"
  ] 
In [30]:
fig = px.scatter(
    df,
    x = 'Hommes_75 ans et plus',
    y=  'Femmes_40 à 59 ans',
    color = 'categorie de dépense',
    size = 'Ensemble_40 à 59 ans',
    width=1000, height=700,
    template="simple_white",
    title = 'Distribution des départements par catégorie de dépense en fonction de la séniorité des individus',
    category_orders={'categorie de dépense':[
        'Moins de 0.5 milliards', 'Entre 0.5 et 1 milliards',
        'Entre 1 et 1.5 milliards', 'Plus de 1.5 milliards'
    ]},
    labels = {
        'Hommes_75 ans et plus':'Hommes de plus de 75 ans',
        'Femmes_40 à 59 ans':'Femmes de 40 à 59 ans'
    }
)
fig.update_yaxes( 
  showgrid=True
)
fig.add_shape( # add a vartical "target" line
    type="line", line_color="salmon", line_width=3, opacity=0.5, line_dash="dot",
    x0=23127.5, x1=23127.5, xref="x", y0=0, y1=350e3, yref="y"
)
fig.add_shape( # add a vartical "target" line
    type="line", line_color="salmon", line_width=3, opacity=0.5, line_dash="dot",
    x0=0, x1=80e3, xref="x", y0=143373.5, y1=143373.5, yref="y"
)
fig.add_annotation( # Text 
    text="23k Hommes de 75 ans et plus", x=23127.5, y=330e3, arrowhead=1, showarrow=False
)
fig.add_annotation( # Text 
    text="140k Femmes de 40 a 59 ans", x=80e3, y=150000, arrowhead=1, showarrow=False
)